import { BaseView, addDomEvents } from '../base';
import { append, empty, first, closest, frag, remove, on, display, trigger } from "mvdom";
import { render } from 'ts/render';
import { formatDate, mom } from 'ts/utils-date';
import { Moment } from 'moment';
import { solar2lunar, formatLunarDate } from 'ts/utils-lunar';
const moment = require('moment');

document.addEventListener("DOMContentLoaded", function (event) {
	on(document, "SHOW_PICKER", ".date-input", (evt) => {
		const targetEl = evt.selectTarget;
		const datePickerEl = first(targetEl, ".DatePicker");
		if (datePickerEl) {
			remove(datePickerEl);
		}
		display(new DatePicker({ targetEl, value: evt.detail.value }), targetEl);
	});
});

// use momentjs
export class DatePicker extends BaseView {
	targetEl?: HTMLElement
	elementInit?: boolean;

	dateStr: any;
	currentMonth: number = 0;
	currentYear: number = 0;
	_onSelectCallback: any;


	constructor(data?: any) {
		super();
		data = data || {};
		this.targetEl = data.targetEl;
		this.elementInit = false;
		// value format yyyy-mm-dd
		this.dateStr = data.value;
	}

	postDisplay() {
		const dateStr = this.dateStr;
		let date: Moment;
		if (!dateStr || dateStr == "") {
			date = moment();
		} else {
			date = moment(dateStr);
		}

		this.currentMonth = date.month();
		this.currentYear = date.year();
		showCalendar.call(this, this.currentMonth);
		selectDate.call(this, date);
		this.elementInit = true;
	}

	// --------- Dom Event Bindings --------- //
	events = addDomEvents(this.events, {
		// click year value to show selection
		"click; .year": (evt: any) => {
			evt.stopPropagation();
			const yearEl = evt.target;
			const selectEl = first(this.el, ".calendar-header select[name='yearSelect']")!;
			selectEl.classList.remove("hide");
			yearEl.classList.add("hide");
			const year = yearEl.getAttribute("data-year") * 1;
			empty(selectEl);
			for (let i = year - 15; i < year + 15; i++) {
				const selected = i == year ? "selected" : "";
				const option = "<option value='" + i + "' " + selected + ">" + i + "</option>";
				const f = frag(option);
				selectEl.appendChild(f);
			}
		},

		// change year value
		"change; select[name='yearSelect']": (evt: any) => {
			const selectEl = evt.target;
			const yearEl = first(this.el, ".calendar-header .year")!;
			selectEl.classList.add("hide");
			yearEl.classList.remove("hide");
			const year = selectEl.value;
			empty(selectEl);
			yearEl.setAttribute("data-year", year);
			yearEl.innerHTML = year;
			this.currentYear = parseInt(year);
			showCalendar.call(this);
		},

		// click icon chevron left/right to change month
		"click;.action": (evt: any) => {
			evt.stopPropagation();
			const targetEl = evt.target;
			const actionEl = closest(targetEl, ".action")!;
			const next = actionEl.classList.contains("actionNext");
			const date = moment([this.currentYear, this.currentMonth, 1]);
			let nextDate;
			if (next) {
				nextDate = date.add(1, "months");
			} else {
				nextDate = date.subtract(1, "months");
			}
			this.currentYear = nextDate.year();
			showCalendar.call(this, nextDate.month());
		},

		"click;.today": (evt: any) => {
			setValue.call(this, moment());
			close.call(this);
		},

		"click;.date": (evt: any) => {
			const dateEL = evt.target;
			// when not show Apply button, click date will apply
			const tdEl = closest(dateEL, "td")!;
			const date = mom(tdEl.getAttribute("data-date"));
			setValue.call(this, date);
			close.call(this);
		}

	});
	// --------- /Dom Event Bindings --------- //

	// --------- Doc Event Bindings --------- //
	docEvents = addDomEvents(this.docEvents, {
		"click": (evt: any) => {
			const targetEl = evt.target;
			const datePickerEl = closest(targetEl, `.${this.name}`);
			if (this.elementInit) {
				if (datePickerEl != this.el) {
					close.call(this);
				}
			}
		}
	});
	// --------- /Doc Event Bindings --------- //
}

// --------- Private View Methods --------- //
function close(this: DatePicker) {
	remove(this.el);
}

function showCalendar(this: DatePicker, month?: number) {
	const calendarCon = first(this.el, ".DatePicker-content")!;
	const calendar = getCalendars.call(this, month);
	append(calendarCon, render("DatePicker-calendar", calendar), "empty");
	const tbodyEl = first(this.el, ".DatePicker-calendar-table tbody")!;
	for (let i = 0; i < calendar.weeks.length; i++) {
		const week = calendar.weeks[i];
		const trEl = render("DatePicker-calendar-tr", { week: week });
		append(tbodyEl, trEl);
	}

}

function getCalendars(this: DatePicker, month?: number) {
	const calendar: any = {};
	month = typeof month == 'undefined' ? this.currentMonth : month;
	const firstDateOfMonth: Moment = moment([this.currentYear, month, 1]);
	this.currentMonth = firstDateOfMonth.month();
	this.currentYear = firstDateOfMonth.year();

	const endDateOfMonth = firstDateOfMonth.clone().add(1, "months").date(0);
	const weeks = [];
	let week = new Array(7);
	for (let i = 0; i < endDateOfMonth.date(); i++) {
		const date = firstDateOfMonth.clone().add(i, 'day');
		const dataValue = date.date();
		const dateFormatStr = formatDate(date);
		week[date.day()] = {
			date,
			dataValue: dataValue,
			dateStr: dateFormatStr,
			currentMonth: true,
			lunar: getLunarDate(date)
		};
		if (date.day() % 7 == 6) {
			weeks.push(week);
			if (endDateOfMonth.date() - i > 1) {
				week = new Array(7);
			}
		}
	}
	if (endDateOfMonth.day() % 7 != 6) {
		weeks.push(week);
	}

	// add last month dates
	for (let i = firstDateOfMonth.day() - 1; i >= 0; i--) {
		const date = firstDateOfMonth.clone().subtract(firstDateOfMonth.day() - i, 'day');
		const dataValue = date.date();
		const dateFormatStr = formatDate(date);
		weeks[0][i] = {
			date,
			dataValue: dataValue,
			dateStr: dateFormatStr,
			currentMonth: false,
			lunar: getLunarDate(date)
		}
	}

	//add next month dates
	let newEndDate = endDateOfMonth;
	for (let i = endDateOfMonth.day() + 1; i <= 6; i++) {
		const date = endDateOfMonth.clone().add(i - endDateOfMonth.day(), 'day');
		const dataValue = date.date();
		const dateFormatStr = formatDate(date);
		weeks[weeks.length - 1][i] = {
			date,
			dataValue: dataValue,
			dateStr: dateFormatStr,
			currentMonth: false,
			lunar: getLunarDate(date)
		}
		newEndDate = date;
	}

	// hide for the 6rd row
	// if (weeks.length < 6) {
	// 	const week = [];
	// 	for (let i = 0; i < 7; i++) {
	// 		const date = newEndDate.clone().add(i + 1, "day");
	// 		const dataValue = date.date();
	// 		const dateFormatStr = formatDate(date);
	// 		week.push({
	// 			date,
	// 			dataValue: dataValue,
	// 			dateStr: dateFormatStr,
	// 			currentMonth: false,
	// 			lunar: getLunarDate(date)
	// 		});
	// 	}
	// 	weeks.push(week);
	// }

	calendar.year = firstDateOfMonth.year();
	calendar.month = firstDateOfMonth.month();
	calendar.monthLabel = `${firstDateOfMonth.month() + 1}月`;
	calendar.weeks = weeks;
	return calendar;
}

function setValue(this: DatePicker, date: Moment) {
	trigger(this.targetEl!, "SET_DATE", { detail: { value: date }, cancelable: false });
}

function selectDate(this: DatePicker, date: Moment) {
	const dateString = formatDate(date);
	const selectedEl = first(this.el, "td .date.selected")!
	if (selectedEl) {
		selectedEl.classList.remove("selected");
	}
	first(this.el, "td[data-date='" + dateString + "'] .date")!.classList.add("selected");
}

// for lunar
function getLunarDate(date: Moment) {
	const lunarDate = solar2lunar(date);
	if (lunarDate.day == 1) {
		return formatLunarDate(lunarDate, "M");
	} else {
		return formatLunarDate(lunarDate, "D");
	}
}
// --------- /Private View Methods --------- //
